package GA;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class GA_Solution implements GA_Param {
	private List<Chromosome> eachPopBestList;
	private List<Chromosome> lasBestChromList;
	private float[] mutateRateArray;
	private int[] gene;

	/**
	 * Constructor.
	 */
	public GA_Solution(){
		eachPopBestList=new ArrayList<Chromosome>(runTimes);
		lasBestChromList=new ArrayList<Chromosome>(10*runTimes); 
		mutateRateArray=new float[CHROM_LENGTH];
	}

	/**
	 * Carry out statistical information of results of top ten optimization.
	 */
	public void countInfo(){
		gene=new int[CHROM_LENGTH];
		for(Chromosome elem:eachPopBestList){
			for(int i=0;i<CHROM_LENGTH;++i){
				gene[i]+=elem.getGene()[i];
			}
		}

		for(int i=0;i<CHROM_LENGTH;++i){
			int g=gene[i];
			gene[i]=g/runTimes;
			// int temp=Math.max(g, runTimes-g);
			if(g==0||g==runTimes){
				mutateRateArray[i]=0.002f;
			}
			else{
				mutateRateArray[i]=0.6f;//(float) 0.09*temp;
			}
		}
		eachPopBestList.clear();
	}

	/**
	 * Further optimized based on the results of top ten optimization.
	 * @param level -It represents the level of optimization.
	 * @throws Exception:
	 */
	public void optimized(int level) throws Exception{
		for(int k=0;k<level;++k){
			countInfo();
			for(int j=0;j<runTimes;++j){
				Population p=new Population(POP_SIZE,CHROM_LENGTH,MAX_ITER);
				p.setPrimaryPop(gene);
				for(int i=0;i<MAX_ITER;++i){ 
					p.repair();
					p.calcFitness();
					List<Chromosome> list=p.select();
					Population.cross(list,PROBABILITY_CROSS*0.5);
					Population.mutate(list,mutateRateArray);
					p.reNewPop(list);
				}
				eachPopBestList.add(p.getBest());
				lasBestChromList.add(p.getBest());
			}	
		}
	}

	/**
	 * Print A certain number of better individual in the eachPopBestList that its capacity is 2*runTimes.
	 */
	public void printBestInfo(){
		lasBestChromList.sort(new Comparator<Chromosome>() {
			@Override
			public int compare(Chromosome o1, Chromosome o2) {
				return o2.getObjValue() - o1.getObjValue();
			}
		});
		for(int i=0;i<runTimes;++i){
			Chromosome elem=lasBestChromList.get(i);
			System.out.print(elem.getObjValue()+"  ");
			for(int g:elem.getGene()){
				System.out.print(g+" ");
			}
			System.out.print("\n");
		}
	}

	/**
	 * Execute function contain iteration of population and print related information.
	 * @param isOptimized: Is it further optimized.
	 * @throws Exception:
	 */
	public void run(boolean isOptimized) throws Exception{
		Population p=new Population(POP_SIZE,CHROM_LENGTH,2*MAX_ITER);
		p.setPrimaryPop();
		for(int i=0;i<2*MAX_ITER;++i){
			p.repair();
			p.calcFitness();
			List<Chromosome> list=p.select();
			Population.cross(list,PROBABILITY_CROSS);
			Population.mutate(list,PROBABILITY_MUTATION);
			p.reNewPop(list);
		}

		// Add the best individual.
		if(isOptimized){
			Chromosome c2=p.getBest();
			eachPopBestList.add(c2);
		}
		else{
			p.printBestInfo(true); 
		}

	}
}

